#include "StdAfx.h"

#pragma warning( disable : 4244 4996)

#include "GDSA.h"
#include "lib/fftw++.h"

#include "utilities.h"

using namespace std;


#define MAX_FREQ 25.0
#define DSA_SMALL_MARGIN 10

#define WINDOW_WIDTH 2

struct threadInvoke1{
	GDSA* p;
	int region;
	int start;
	int end;
	DSAOutput *out;
};

UINT DSA_Working_Thread( LPVOID pParam ){
	threadInvoke1 *ti=(threadInvoke1* )pParam;
	return ti->p->DoCalc(ti->region,ti->start,ti->end, ti->out);
}

GDSA::~GDSA(void)
{

}

UINT GDSA::DoCalc(int region,int start,int end, DSAOutput* dsao)
{
	//vector<int> LEs=getHemiChannels(0),REs=getHemiChannels(1);
	//for(int i=0;i<LEs.size();i++)

	const int SR=dataStore->GetSamplingRate();
	if(start==0 && end==0)
	{
		start=0;
		end=dataStore->GetChannel(0).data.size();
	}
	DSAOutput &tmpout=*dsao;
	tmpout.region=region;
	tmpout.begintime=start/(double)SR;
	tmpout.duration=(end-start)/SR;
	if(tmpout.duration<3)
		return 0;

	unsigned int n=SR*WINDOW_WIDTH;
	unsigned int np=n/2+1;
	double *f=FFTWdouble(n);
	Complex *g=FFTWComplex(np); 
	rcfft1d Forward(n,f,g); 
	tmpout.data.resize(tmpout.duration);
	for(size_t i=0;i<tmpout.duration;i++)
		tmpout.data[i].resize(MAX_FREQ*n/SR,0.0);
	int counter=0;
	for(int i=0;i<dataStore->GetChannelCount();i++)
	{
		if(!(dataStore->GetChannel(i).electrode.region & region))
			continue;
		counter++;
		for(unsigned int time=0;time<tmpout.duration-1;time++){
				for(unsigned int j=0; j < n; j++) dataStore->GetRefData(i,j+time*SR,f[j]);
				Forward.fft(f,g);
				for(UINT k=0;k<MAX_FREQ*n/SR;k++)
					tmpout.data[time][k]+=g[k].real()*g[k].real()+g[k].imag()*g[k].imag();
		}
	}
	tmpout.max=0.0;
	for(unsigned int i=0;i<tmpout.duration-1;i++)
		for(UINT j=0;j<MAX_FREQ*n/SR;j++){
					tmpout.data[i][j]/=counter;
					tmpout.max =( tmpout.max<tmpout.data[i][j] && j!=0) ? tmpout.data[i][j] : tmpout.max;
		}
#ifdef _DEBUG
	ofstream ofs("dsa.txt");

	/*for(int i=0;i<m;i++)
	ofs << out[i].real() <<"   " << out[i].imag() << endl;
	ofs<<endl<<endl;*/
	for(unsigned int i=0;i<tmpout.duration-1;i++){
				for(UINT j=0;j<MAX_FREQ*n/SR;j++)
					ofs<<tmpout.data[i][j]<<" ";
				ofs<<endl;
	}
	ofs.close();
#endif

	FFTWdelete(f);
	FFTWdelete(g);

	WBH_Close(wb);
	return 0;
}

bool GDSA::StartCalc(int region,int start,int end, int outIndex)
{

	threadInvoke1 ti;
	ti.region=region;
	ti.p=this;
	ti.start=start;
	ti.end=end;
	ti.out = &out[outIndex];

	wb.SetDefaultPrompt(L"Calculating DSA...");
	CWinThread *thread=AfxBeginThread(DSA_Working_Thread,(void*)&ti);
	if(!thread)
		return false;

	wb.DoModal();//show wb
	//DWORD ret=-1;
	//GetExitCodeThread(thread->m_hThread,&ret);

	//return (ret==-1)?false:true;


	//UpdateBitmap(n);
	return true;

}



int GDSA::FindInOut(int region, int b, int e)
{
	int ret=-1;
/*	for(int i=0;i<out.size();i++){
		if(out[i].channel==ch && out[i].b==b && out[i].e==e){
			ret=i;break;
		}
	}*/
	return ret;
}

void GDSA::DrawSingleDSA(Bitmap *bmp,int w,int h, int indexInOut){
	Graphics* graph = Graphics::FromImage(bmp);
	graph->Clear(Color(0,0,0));

	const int SR=dataStore->GetSamplingRate();

	const int graphWidth=w/*-MARGIN_WIDTH-DSA_SMALL_MARGIN*/;
	const int graphHeight=h/*-2*DSA_SMALL_MARGIN*/;
	const unsigned int N=out[indexInOut].duration;
	const double wPerDot=graphWidth/(out[indexInOut].duration-1.0);
	const double hPerDot=graphHeight/(MAX_FREQ*WINDOW_WIDTH-1.0);

	for(UINT i=0;i<N-1;i++){
		for(UINT j=1;j<(UINT)(MAX_FREQ*WINDOW_WIDTH);j++)
		{
			double x = wPerDot*i;
			double y = hPerDot*(j-1);
			double r,g,b;
			HSLtoRGB(80+160*out[indexInOut].data[i][j]/out[indexInOut].max , 240 , 120 , &r , &g , &b );
			SolidBrush sb(Color(r,g,b));
			graph->FillRectangle(&sb,RectF(x,y,ceil(wPerDot),ceil(hPerDot)));
		}
	}
	
	SAFE_DELETE(graph);
	
}

/*std::vector<int> GDSA::getHemiChannels(bool hemi){
	vector<int> ret;
	for(int i=0;i<dataStore->GetChannelCount();i++)
	{
		if(dataStore->GetChannel(i).hemisphere==hemi)
			ret.push_back(i);
	}
	return ret;
	}*/

void GDSA::Draw(CDC* pdc, const CRect& rcBounds, const CRect& rcInvalid){
	TCHAR buf[256];
	TCHAR strTitle[256];

	Rect rc(rcBounds.left,rcBounds.top,rcBounds.right,rcBounds.bottom);
	Bitmap bmp(rcBounds.right,rcBounds.bottom);
	FontFamily  fontFamily(TEXT_FONT);
	Graphics graphics(pdc->GetSafeHdc()); 

	// Create a Graphics object that is associated with the image.
	Graphics* graph = Graphics::FromImage(&bmp);
	graph->Clear(Color(0,0,0));

	Font         font1(&fontFamily, AXIS_TEXT_SIZE, FontStyleBold, UnitPoint);
	SolidBrush   sb1(Color(255,255,255));

	Bitmap *tmpBmp=NULL;
	int graphWidth=0/*-MARGIN_WIDTH-DSA_SMALL_MARGIN*/;
	int graphHeight=0/*-2*DSA_SMALL_MARGIN*/;

	switch(layout){
		case WA_DSA_LAYOUT_ALL:
			if(out[0].data.empty())
				StartCalc(~(UINT)0);
			graphWidth=rcBounds.Width()-MARGIN_WIDTH-DSA_SMALL_MARGIN;
			graphHeight=rcBounds.Height()-2*MARGIN_WIDTH;
			tmpBmp=new Bitmap(graphWidth,graphHeight);
			DrawSingleDSA(tmpBmp,graphWidth,graphHeight, 0);
			graph->DrawImage(tmpBmp,PointF(MARGIN_WIDTH,MARGIN_WIDTH));
			graph->DrawRectangle(new Pen(Color(255,255,255), 2.0), RectF(MARGIN_WIDTH,MARGIN_WIDTH,graphWidth,graphHeight));//draw borders
			//draw x axis
			for(int i=0;i<AXIS_SEGMENT;i++){
				int x=MARGIN_WIDTH+graphWidth/AXIS_SEGMENT*i;
				int y=MARGIN_WIDTH+graphHeight;
				graph->DrawLine(new Pen(Color(255,255,255)),x,y,x,y-15);
			}
			//draw y axis
			for(int i=0;i<AXIS_SEGMENT+1;i++){
				int x=MARGIN_WIDTH;
				int y=MARGIN_WIDTH+graphHeight/AXIS_SEGMENT*i;
				graph->DrawLine(new Pen(Color(255,255,255)),x,y,x+15,y);
				swprintf(buf,256,L"%.1f",(double)MAX_FREQ/AXIS_SEGMENT*i);
				graph->DrawString(buf,-1,&font1,PointF(x-MARGIN_WIDTH+5.0,y-AXIS_TEXT_SIZE),&sb1);
			}
			swprintf(strTitle,256,L"DSA Graph @ Time %g to %g",out[0].begintime,out[0].begintime+out[0].duration);
			break;
		case WA_DSA_LAYOUT_HEMICMP:
			break;
		default:
			AfxMessageBox(_T("Invalid Parameters!"));
	}

	Font         font(&fontFamily, TITLE_SIZE, FontStyleBold, UnitPoint);
	RectF        rTitle(0.0f, 0.0f, rcBounds.Width(), MARGIN_WIDTH);
	StringFormat stringFormat;
	SolidBrush   sb2(Color( 255, 255, 0));
	stringFormat.SetAlignment(StringAlignmentCenter);
	graph->DrawString(strTitle, -1, &font, rTitle, &stringFormat, &sb2);//draw title

	graphics.DrawImage(&bmp,rcBounds.left,rcBounds.top,rcBounds.right,rcBounds.bottom);
	SAFE_DELETE(tmpBmp);
	SAFE_DELETE(graph);

}